/// ------------------------------------------------------------------------------------------------------------------------------------
///
/// MIT License
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///
/// Copyright (c) 2022 ycz. All rights reserved.
///
/// Created by ycz on 2022/1/9.
///
/// @file  y_log.h
///
/// @brief
///     y_log 是一种用于嵌入式设备简单调试的日志，可以方便的将需要输出的信息进行格式化显示。
///
/// ------------------------------------------------------------------------------------------------------------------------------------



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 防止当前头文件被重复引用
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifndef _Y_LOG_H
#define _Y_LOG_H



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 头文件
/// ------------------------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 兼容 c++
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义 - 版本号
/// ------------------------------------------------------------------------------------------------------------------------------------

#define Y_LOG_VERSION_MAJOR  0  ///< 版本信息 主版本   ( 主架构变化 )
#define Y_LOG_VERSION_MINOR  2  ///< 版本信息 次版本   ( 单个功能增加或修改 )
#define Y_LOG_VERSION_PATCH  1  ///< 版本信息 补丁版本  ( bug修复 )



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义 - 日志设置
/// ------------------------------------------------------------------------------------------------------------------------------------

#define Y_LOG_SWITCH_TIME    1  ///< 日志时间打印开关                  0=关闭  1=打开
#define Y_LOG_SWITCH_COLOR   0  ///< 日志颜色打印开关                  0=关闭  1=打开
#define Y_LOG_SWITCH_ASSERT  2  ///< 断言日志打印开关 (Assert)         0=关闭  1=打开  2=只断言不打印
#define Y_LOG_SWITCH_ERROR   1  ///< 错误日志打印开关 (Error)          0=关闭  1=打开
#define Y_LOG_SWITCH_WARN    1  ///< 警告日志打印开关 (Warn)           0=关闭  1=打开
#define Y_LOG_SWITCH_INFO    1  ///< 信息日志打印开关 (Info)           0=关闭  1=打开
#define Y_LOG_SWITCH_DEBUG   1  ///< 调试日志打印开关 (Debug)          0=关闭  1=打开
#define Y_LOG_SWITCH_VERBOSE 0  ///< 详细日志打印开关 (Verbose)        0=关闭  1=打开
#define Y_LOG_SWITCH_DATA    1  ///< 数据日志打印开关 (Data)           0=关闭  1=打开
#define Y_LOG_SWITCH_VERSION 1  ///< 版本日志打印开关 (version)        0=关闭  1=打开



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义 - 日志格式
/// ------------------------------------------------------------------------------------------------------------------------------------

/// 日志时间格式
#if Y_LOG_SWITCH_TIME
#    include "y_time.h"
#    define Y_TIME_STR y_time_get_str()  ///< 获取时间字符串 (若开启时间打印 需要设置时间戳字符串获取函数)
#else
#    define Y_TIME_STR ""  ///< 时间字符串
#endif

/// 日志颜色格式
#if Y_LOG_SWITCH_COLOR
#    define Y_COLOR_DATA    "\033[32m"  ///< 数据日志颜色 (Data)    绿色
#    define Y_COLOR_ASSERT  "\033[31m"  ///< 断言日志颜色 (Error)   红色
#    define Y_COLOR_ERROR   "\033[31m"  ///< 错误日志颜色 (Error)   红色
#    define Y_COLOR_WARN    "\033[33m"  ///< 警告日志颜色 (Warn)    黄色
#    define Y_COLOR_INFO    "\033[37m"  ///< 信息日志颜色 (Info)    白色
#    define Y_COLOR_DEBUG   "\033[34m"  ///< 调试日志颜色 (Debug)   蓝色
#    define Y_COLOR_VERBOSE "\033[32m"  ///< 详细日志颜色 (Verbose) 绿色
#    define Y_COLOR_END     "\033[0m"   ///< 颜色日志结束
#else
#    define Y_COLOR_DATA     ///< 数据日志颜色 (Data)    绿色
#    define Y_COLOR_ASSERT   ///< 断言日志颜色 (Error)   红色
#    define Y_COLOR_ERROR    ///< 错误日志颜色 (Error)   红色
#    define Y_COLOR_WARN     ///< 警告日志颜色 (Warn)    黄色
#    define Y_COLOR_INFO     ///< 信息日志颜色 (Info)    白色
#    define Y_COLOR_DEBUG    ///< 调试日志颜色 (Debug)   蓝色
#    define Y_COLOR_VERBOSE  ///< 详细日志颜色 (Verbose) 绿色
#    define Y_COLOR_END      ///< 颜色日志结束
#endif



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义 - 函数声明
/// ------------------------------------------------------------------------------------------------------------------------------------

void y_log_print(uint8_t log_type, int line, const char *fun, char *buf, ...);         ///< 打印常规日志
void y_log_data(int line, const char *fun, char *name, uint8_t *data, uint16_t size);  ///< 打印数据日志
void y_log_version(char *MODULE, uint8_t MAJOR, uint8_t MINOR, uint8_t PATCH);         ///< 打印模块版本信息



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义 - 日志打印格式
/// ------------------------------------------------------------------------------------------------------------------------------------

// 断言日志打印格式
#if (Y_LOG_SWITCH_ASSERT == 1)
#    define YLOGA(EXPR)                                                                                                                                                            \
        do {                                                                                                                                                                       \
            if (!(EXPR)) {                                                                                                                                                         \
                y_log_print(1, __LINE__, __FUNCTION__, "%s assert error", #EXPR);                                                                                                  \
                return;                                                                                                                                                            \
            }                                                                                                                                                                      \
        } while (0)
#    define YLOGA_NULL(EXPR)                                                                                                                                                       \
        do {                                                                                                                                                                       \
            if (!(EXPR)) {                                                                                                                                                         \
                y_log_print(1, __LINE__, __FUNCTION__, "%s assert error", #EXPR);                                                                                                  \
                return NULL;                                                                                                                                                       \
            }                                                                                                                                                                      \
        } while (0)
#    define YLOGA_FALSE(EXPR)                                                                                                                                                      \
        do {                                                                                                                                                                       \
            if (!(EXPR)) {                                                                                                                                                         \
                y_log_print(1, __LINE__, __FUNCTION__, "%s assert error", #EXPR);                                                                                                  \
                return false;                                                                                                                                                      \
            }                                                                                                                                                                      \
        } while (0)
#elif (Y_LOG_SWITCH_ASSERT == 2)
#    define YLOGA(EXPR)                                                                                                                                                            \
        if (!(EXPR))                                                                                                                                                               \
        return
#    define YLOGA_NULL(EXPR)                                                                                                                                                       \
        if (!(EXPR))                                                                                                                                                               \
        return NULL
#    define YLOGA_FALSE(EXPR)                                                                                                                                                      \
        if (!(EXPR))                                                                                                                                                               \
        return false
#else
#    define YLOGA(EXPR)
#    define YLOGA_NULL(EXPR)
#    define YLOGA_FALSE(EXPR)
#endif

// ERROR 错误日志打印格式
#if Y_LOG_SWITCH_ERROR
#    define YLOGE(format, ...) y_log_print(2, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)
#else
#    define YLOGE(format, ...)
#endif

// WARN 警告日志打印格式
#if Y_LOG_SWITCH_WARN
#    define YLOGW(format, ...) y_log_print(3, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)
#else
#    define YLOGW(format, ...)
#endif

// INFO 信息日志打印格式
#if Y_LOG_SWITCH_INFO
#    define YLOGI(format, ...) y_log_print(4, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)
#else
#    define YLOGI(format, ...)
#endif

// DEBUG 调试日志打印格式
#if Y_LOG_SWITCH_DEBUG
#    define YLOGD(format, ...) y_log_print(5, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)
#else
#    define YLOGD(format, ...)
#endif

// VERBOSE 详细日志打印格式
#if Y_LOG_SWITCH_VERBOSE
#    define YLOGV(format, ...) y_log_print(6, __LINE__, __FUNCTION__, format, ##__VA_ARGS__)
#else
#    define YLOGV(format, ...)
#endif

// DATA 数据日志打印格式
#if Y_LOG_SWITCH_DATA
#    define YLOG_DATA(name, data, size) y_log_data(__LINE__, __FUNCTION__, name, data, size)
#else
#    define YLOG_DATA(name, data, size)
#endif

// VERSION 版本号打印格式
#if Y_LOG_SWITCH_VERSION
#    define YLOG_VERSION(MODULE, MAJOR, MINOR, PATCH) y_log_version(MODULE, MAJOR, MINOR, PATCH)
#else
#    define YLOG_VERSION(MODULE, MAJOR, MINOR, PATCH)
#endif

// 初始化日志打印格式
#define YLOG_INIT(EXPR) YLOGI("init %s    %s", (EXPR) ? "OK  " : "FAIL", #EXPR)

// LF,CR,CRLF 回车换行打印
#define YLOG_LF()       printf("\n")
#define YLOG_CR()       printf("\r")
#define YLOG_CRLF()     printf("\r\n")



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 函数 API
/// ------------------------------------------------------------------------------------------------------------------------------------

void y_log_print_version();  ///< 打印模块版本号



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 条件编译结尾
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef __cplusplus
}
#endif  // __cplusplus 兼容 c++
#endif  // _Y_LOG_H 防止当前头文件被重复引用